﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Utility.FSM
{
	public class FSM
	{
		public static readonly string RootNmae = "Root";

		Dictionary<string, State> fullnameStateDict = new Dictionary<string, State> ();

		public string Name { get; private set; }
		public State Root { get; private set; }

		//constructor
		public FSM (string name)
		{
			Name = name;
			Root = new State (RootNmae, this, null);
			fullnameStateDict[Root.Fullname] = Root;
		}

		public bool Contains (State state)
		{
			if (state == null)
			{
				return false;
			}
			return fullnameStateDict[state.Fullname] == state;
		}

		public State AddNewState (string name, State upperState, IStateScript script = null)
		{
			var state = new State (name, this, upperState, script);
			var fullname = state.Fullname;
			if (fullnameStateDict.ContainsKey (fullname))
			{
				throw new System.Exception ("repeated state name: " + fullname);
			}
			else
			{
				fullnameStateDict[fullname] = state;
				return state;
			}
		}

		public State AddNewState<TStateScript> (string name, State upperState)
			where TStateScript : IStateScript, new()
		{
			var script = new TStateScript ();
			return AddNewState (name, upperState, script);
		}

		public State AddNewState<TStateScript> (State upperState)
			where TStateScript : IStateScript, new()
		{
			var type = typeof (TStateScript);
			var nameAttributes = type.GetCustomAttributes (typeof (StateNameAttribute), false);
			string name = nameAttributes.Length > 0 ? (nameAttributes[0] as StateNameAttribute).name : type.Name;
			return AddNewState<TStateScript> (name, upperState);
		}

		public State GetState (string fullName, bool throwException = false)
		{
			State ret;
			if (!fullnameStateDict.TryGetValue (fullName, out ret))
			{
				if (throwException)
				{
					throw new System.Exception ("Cannot find state: " + fullName);
				}
			}
			return ret;
		}

		public Agent CreateAgent (string name, IAgentScript script = null)
		{
			var agent = new Agent (this, name, script);
			return agent;
		}

		public Agent CreateAgent<TAgentScript> (string name)
			where TAgentScript : IAgentScript, new()
		{
			var script = new TAgentScript ();
			var agent = new Agent (this, name, script);
			return agent;
		}
	}
}